#include "include.h"
#include "func.h"
#include "func_usbdev.h"

f_ude_t f_ude;

#if FUNC_USBDEV_EN

//u8 ex_mic_vol(void)  //USB_device mic初始化音量
//{
//    return 0xD1;
//}
//
//u8 ex_spk_vol(void) //扬声器初始化音量
//{
//    return 0x7F;
//}

//是否需要PC端弹出U盘功能，需要则打开下方函数medium_removal_eanble()即可
//AT(.usbdev.com.ep)
//u8 medium_removal_eanble(void)
//{
//	return 1;
//}

//部分typec耳机可能有兼容性问题，打开下方函数clos_dm_pull_up（）试试
//bool clos_dm_pull_up(void)
//{
//    return true;
//}

//AT(.usbdev.com.audio)
//void usbdev_recv_pcm_callback(void *buf, uint samples) {}   //引出PC=>DAC中间的数据流,方便客户自行处理数据

//AT(.usbdev.com.storage)
//void AB_set_udisk_time(u8 *get_time_buf, u8 len)
//{
//    /*
//    //使用自家小工具更新时间：
//    get_time_buf 时间数据
//    格式
//    buf[0] yy年
//    buf[1] mm月
//    .
//    .
//    .
//    buf[5] ss秒
//
//    */
//    my_printf("get_time_buf:\n");
//    my_print_r(get_time_buf, len);
//}

/*********************************
 * name : set_usb_dev_read_only
 * func : 设置usb从机存储设备为 只读
 * note : 取消注释，在需要的位置放置即可
 *        在枚举前放置 - PC显示U盘只读，不能够写入数据
 *        在枚举后放置 - PC写入数据为假写入，即没有将数据写入硬件
*********************************/
//AT(.com_text.usbdev)
//bool set_usb_dev_read_only(void){//设置USB从机存储设备只读(软:跳过写入)
//    return true;
//}

void usbmic_sdadc_process(u8 *ptr, u32 samples, int ch_mode);
void uda_set_by_pass(u8 bypass);
#if UDE_MIC_TO_DAC
void dac_src1_init(void);
void dac_src1_spr_set(uint spr);
void usbmic_to_src1_process(u8 *ptr, u32 samples, int ch_mode);
AT(.usbdev.com.audio)
void usb_adc_ext(u8 *ptr, u32 samples, int ch_mode)
{
    usbmic_to_src1_process(ptr, samples, ch_mode);
    usbmic_sdadc_process(ptr, samples, ch_mode);
}
#endif


#if IIS_MASTER_RX_2_UDE_MIC
#define IIS_DMA_SAMPLES  64

AT(.com_text.iis_ext_cst)
const char str_iisrx_info_usbmic[] = "IISRX: samples = %d, isrcnt = %d (SR_%d)\n";

u8 buf_ptr[IIS_DMA_SAMPLES*2*3] AT(.usb_iis_buf);
AT(.com_text.iis_ext)
void iis_2_usbmic(void *buf, u32 samples, bool iis_32bit)
{
    u16 *buf_p;
    buf_p = (u16 *)buf_ptr;
//    memset(buf, 0, samples);
    memset(buf_p, 0, IIS_DMA_SAMPLES*2*3);
    u32 *ptr32 = (u32*)buf;
    u16 *ptr16 = (u16*)buf;
    if (iis_32bit) {  //IIS_32BIT
        samples = samples / 2;
        for (int i = 0; i < samples; i++) {  //32BIT ->16bit  for dac out
           ptr16[2*i] =  (u16)(ptr32[2*i] >> 16);
           ptr16[2*i+1] =  (u16)(ptr32[2*i+1] >> 16);
        }
    }

//    my_print_r(buf, samples);
    //dual ->mono
    for(int i = 0; i < samples; i++) {
//        ptr16[i] = ptr16[2*i]/2 + ptr16[2*i + 1]/2;
        ptr16[i] = ptr16[2*i];
    }
//    my_print_r(buf, samples);
    u16 *buf_pp = buf;
    for(u8 i = 0; i < samples; i++) {
        buf_p[3*i + 0] = buf_pp[i];
        buf_p[3*i + 1] = buf_pp[i];
        buf_p[3*i + 2] = buf_pp[i];
    }

    buf = buf_ptr;
    samples *= 3;
//    my_print_r(buf, samples);
    //debug_info,调试完后可以关掉
#if 1
    static u32 ticks = 0;
    static u32 isr_cnt = 0;
    isr_cnt++;
    if (tick_check_expire(ticks,1000)) {
        printk(str_iisrx_info_usbmic,samples, isr_cnt, samples*isr_cnt);
        isr_cnt = 0;
        ticks = tick_get();
    }
#endif
#if UDE_MIC_TO_DAC
    usb_adc_ext(buf, samples, 0);
#else
    usbmic_sdadc_process(buf, samples, 0);  //向USBMIC推数据,此函数内部有2K的缓存做同步
#endif
}

#define IIS_DMABUF_LEN   (IIS_DMA_SAMPLES * 2 * 2 *4)  //tx,rx double_buf, one_sample_4byte
extern u8 iis_dmabuf[IIS_DMABUF_LEN];                               //若iis_cfg.mode中有RAMTX或RAMRX,需要该dmabuf做中断缓存
void iis2usbmic_init(void)                                          //iis初始化, 需要在dac_init之后调用
{
    static iis_cfg_t iis2usbmic_cfg;
    memset(&iis2usbmic_cfg,0x00, sizeof(iis2usbmic_cfg));
    iis2usbmic_cfg.mode        = IIS_SLAVE_RAMRX;
    iis2usbmic_cfg.iomap       = IIS_G1;
    iis2usbmic_cfg.bit_mode    = IIS_32BIT;
    iis2usbmic_cfg.data_mode   = IIS_DATA_NORMAL;
    iis2usbmic_cfg.mclk_sel    = IIS_MCLK_256FS;
    iis2usbmic_cfg.mclk_out_en = IIS_MCLK_OUT_DIS;
    if (iis2usbmic_cfg.mode & IISCFG_DMA) {
        printf("iis_dma config run\n");
        iis2usbmic_cfg.dma_cfg.samples = IIS_DMA_SAMPLES;
        iis2usbmic_cfg.dma_cfg.dmabuf_ptr = iis_dmabuf;
        iis2usbmic_cfg.dma_cfg.dmabuf_len = IIS_DMABUF_LEN;
        iis2usbmic_cfg.dma_cfg.iis_isr_rx_callbck = iis_2_usbmic;  //iis_rx接收完一个DMA后起中断,回调该函数,可以从buf中取出接收到数据
        iis2usbmic_cfg.dma_cfg.iis_isr_tx_callbck = NULL;          //iis_tx发送完一个DMA后起中断,要求向buf中填入数据,以备下一次发送
    }
    iis_cfg_init(&iis2usbmic_cfg);
}
#endif  //IIS_MASTER_RX_2_UDE_MIC

void micdnr_process(void *buf, u32 samples);
#if SD_USB_MUX_IO_EN
unsigned long pu300_bak, pu_bak,dir_bak;
#endif

#if USBDEV_REC_EN
void usbdev_rec_start(void);
void usbdev_rec_stop(void);

AT(.text.func.usbdev)
void usbdev_rec_init(void)
{
    rec_src.spr = SPR_48000;
    rec_src.source_start = usbdev_rec_start;
    rec_src.source_stop  = usbdev_rec_stop;
    rec_src.nchannel = 0x22;
}
#endif

u8 usb_swicth = 0;
bool usb_karaok_en = false;
AT(.com_text.karaok.proc)
u8 switch_on_off_usb_t(void)
{
    return usb_karaok_en;
}

AT(.text.func.usbdev)
void ude_mic_start(void)
{
#if IIS_MASTER_RX_2_UDE_MIC
    iis_start();
    return;
#endif

#if UDE_MIC_KARAOK_EN
  usb_karaok_en = true;
#endif

#if AUX_MIC_TWO_CHANNLE
    usb_swicth = 1;
#elif !UDE_MIC_KARAOK_EN
    audio_path_init(AUDIO_PATH_USBMIC);
    audio_path_start(AUDIO_PATH_USBMIC);
    dac_spr_set(SPR_48000);
#endif
}

AT(.text.func.usbdev)
void ude_mic_stop(void)
{
#if IIS_MASTER_RX_2_UDE_MIC
    iis_stop();
    return;
#endif

  usb_karaok_en = false;

#if !AUX_MIC_TWO_CHANNLE && !UDE_MIC_KARAOK_EN
    audio_path_exit(AUDIO_PATH_USBMIC);
#endif
}

AT(.com_text.karaok.proc)
u8 switch_on_off_usb_aux(void)
{
    return usb_swicth;
}

//开启电脑端同步usb mic音量
//AT(.usbdev.com.audio)
//bool ude_karaok_mic_vol_en(void)
//{
//    return 1;
//}
//设置增益，值越大声音越小
//AT(.usbdev.com.audio)
//u8 ude_karaok_mic_vol_level(void)
//{
//    return 14;
//}

AT(.usbdev.com.audio)
u8 switch_on_off_usb_aux_t(void){
    return AUX_MIC_TWO_CHANNLE|UDE_MIC_STEREO;
}

#if USB_WINDOW_VOL_DB_EN
u8 ude_get_sys_volume(void)
{
    if (sys_cb.vol > VOL_MAX) {
        return VOL_MAX;
    }
    return sys_cb.vol;
}

u8 ude_get_sys_vol_max(void)
{
    return VOL_MAX;
}
#else
u8 ude_get_sys_volume(void)
{
    return sys_cb.vol;
}

u8 ude_get_sys_vol_level(void)
{
    return 256 / VOL_MAX;
}
#endif

void ude_set_sys_volume(u8 vol)
{
    bsp_set_volume(vol);
}

#if UDE_STORAGE_EN
AT(.text.func.usbdev)
void ude_sdcard_switch(u8 dev)
{
//    printf("%s, %d, %d\n", __func__, f_ude.cur_dev, dev);
    if (f_ude.cur_dev != dev) {
        ude_sd_remove();
        f_ude.cur_dev = dev;
        fsdisk_callback_init(f_ude.cur_dev);
        f_ude.dev_change = 1;
    } else {
        sd0_init();
    }
}

AT(.text.func.usbdev)
void ude_sdcard_change_process(void)
{
    static u8 cnt_s = 0;
    if (f_ude.dev_change) {
        cnt_s++;
        if (cnt_s >= 5) {
            f_ude.dev_change = 0;
            sd0_init();
        }
    } else {
        cnt_s = 0;
    }
}
#endif // UDE_STORAGE_EN


#if 0   //USBMIC 增加独立DRC 限幅器的使用示例
//u8 usbmic_dump_head_buf[14*2];   //管理文件头需要的buf  //可以dump数据查看
//u8 usbmic_dump_dma_buf[14+128 + 14 + 128];  //DMA需要的BUF
//dump_buf_huart_init();
//AT(.com_text.usbdbg)
//const char strsp[] = "[%d]";
//   DRC初始化需要调用以下两个函数，usbmic_sdadc_process_ex要注册到bsp_audio.c对应的回调函数中。
//   exlib_drc_v1_init(0);
//   exlib_drc_v1_set_by_res(&RES_BUF_DRC_NORMAL_DRC,&RES_LEN_DRC_NORMAL_DRC);

#define USBMIC_PRE_GAIN   GAIN_DIG_P12DB //GAIN_DIG_N0DB// GAIN_DIG_P12DB
AT(.com_text.usb_mic)
void usbmic_sdadc_process_ex(u8 *ptr, u32 samples, int ch_mode)
{
//    static u32 ticks = 0;
//    if (tick_check_expire(ticks,1000)) {
//        printf(strsp,samples);
//        ticks = tick_get();
//    }
//    memcpy(&usbmic_dump_dma_buf[14+128],ptr,128);  //保存原始数据
    s16 *pcm16 = (s16*)ptr;   //DRC 处理
    for(int i = 0; i < samples; i++){
        s32 dat32 = pcm16[i] ;
        dat32 = (dat32 * (int)USBMIC_PRE_GAIN) >> 13 ;
        exlib_drc_v1_mono_process(&dat32);
        pcm16[i] = (s16)dat32;
    }
//    u16 *pcml = (u16*)&usbmic_dump_dma_buf[14+128];
//    u16 *pcmr = (u16*)ptr;
//    u32 *mix32 = (u32*)&usbmic_dump_dma_buf[14];
//    for(int i = 0; i < 64; i++) {
//        mix32[i] = (pcml[i]<<16) | pcmr[i];
//    }
//    dump_dma_wait();
//    dump_put2ram(usbmic_dump_dma_buf,mix32,256,0);
//    dump_dma_kick(usbmic_dump_dma_buf,14 + 256);
    usbmic_sdadc_process(ptr,samples,ch_mode);
}
#endif

#if UDE_MIC_DNR_EN
AT(.com_text.ude_mic_dnr)
void ude_micdnr_process(void *buf, u32 samples)
{
    micdnr_process(buf, samples);
}
#endif // UDE_MIC_DNR_EN
AT(.text.func.usbdev)
void func_usbdev_process(void)
{
    func_process();
    usb_device_process();
    f_ude.rw_sta = sd0_get_rw_sta();
}

AT(.text.func.usbdev)
void func_usbdev_mp3_res_play(u32 addr, u32 len)
{
    if (len == 0) {
        my_printf("mp3_len_0\n");
        return;
    }

    uda_set_by_pass(1);

    DACDIGCON0 &= ~BIT(6);
    adpll_spr_set(DAC_OUT_SPR);

    dac_fade_out();
    dac_fade_wait();

//    bsp_change_volume(WARNING_VOLUME);
    mp3_res_play(addr, len);
//    bsp_piano_warning_play(WARNING_TONE, TONE_MAX_VOL);
    dac_fade_out();

    dac_fade_wait();
    bsp_change_volume(sys_cb.vol);

    dac_fade_in();

    adpll_spr_set(DAC_OUT_48K);
    dac_spr_set(0);                 //samplerate 48K
    DACDIGCON0 |= BIT(6);           //Src0 Sample Rate Synchronization Enable

    uda_set_by_pass(0);
}

static void func_usbdev_enter(void)
{
#if UDE_HID_BACKSTAGE_EN
    if (dev_is_online(DEV_USBPC)) {
        usb_device_exit();
    }
#endif
#if SYS_KARAOK_EN && AUX_MIC_TWO_CHANNLE
    bsp_karaok_init(AUDIO_PATH_KARAOK, FUNC_USBDEV);
#endif
    f_ude.vol = sys_cb.vol;         //restore system volume
#if SD_USB_MUX_IO_EN
    sd0_stop(1);
	sd_disable_user();
	SD_DAT_DIS_UP();
	pu300_bak = pu300;pu_bak = pu;dir_bak = dir;
	FUNCMCON0 = 0x0f;                       //关SD0 Mapping
	delay_us(1);
#endif
    if (!dev_is_online(DEV_USBPC)) {
        func_cb.sta = FUNC_NULL;
        return;
    }
#if UDE_MIC_DNR_EN
    micdnr_level_init(UDE_MIC_DNR_LEVEL);
#endif

    f_ude.cur_dev = DEV_SDCARD;
    f_ude.dev_change = 0;
    func_usbdev_enter_display();
    led_idle();
    func_cb.mp3_res_play = func_usbdev_mp3_res_play; //mp3_res_play;
#if WARNING_FUNC_USBDEV
    mp3_res_play(RES_BUF_PC_MODE_MP3, RES_LEN_PC_MODE_MP3);
#endif // WARNING_FUNC_USBDEV

#if UDE_SPEAKER_EN
#if !SYS_KARAOK_EN
    adpll_spr_set(1);
#endif
    dac_spr_set(0);                 //samplerate 48K
    DACDIGCON0 |= BIT(6);           //Src0 Sample Rate Synchronization Enable
    dac_fade_in();
#endif // UDE_SPEAKER_EN

#if UDE_STORAGE_EN

#if UDE_STOAGE_FLASH_EN
    if(spiflash1_manu_id_read()){
        sys_cb.cur_dev = DEV_SPIFLASH;
        fsdisk_callback_init(f_ude.cur_dev);
    } else
#endif // UDE_STOAGE_FLASH_EN

    if (dev_is_online(DEV_SDCARD) || dev_is_online(DEV_SDCARD1)) {
        if (dev_is_online(DEV_SDCARD)) {
            f_ude.cur_dev = DEV_SDCARD;
        } else if (dev_is_online(DEV_SDCARD1)) {
            f_ude.cur_dev = DEV_SDCARD1;
        }
        fsdisk_callback_init(f_ude.cur_dev);
        fs_mount();
    }

#endif // UDE_STORAGE_EN

#if SYS_KARAOK_EN && UDE_MIC_KARAOK_EN
    bsp_karaok_init(AUDIO_PATH_KARAOK, FUNC_USBDEV);
    dac_fade_in();
#endif

#if USBDEV_REC_EN
    usbdev_rec_init();
#endif
    usb_device_enter(UDE_ENUM_TYPE);

#if UDE_MIC_TO_DAC
    dac_src1_init();
    dac_src1_spr_set(0);
#endif

#if IIS_MASTER_RX_2_UDE_MIC
    iis2usbmic_init();
#endif
}

static void func_usbdev_exit(void)
{
#if SYS_KARAOK_EN && AUX_MIC_TWO_CHANNLE
    usb_swicth = 0;
    bsp_karaok_exit(AUDIO_PATH_KARAOK);
#endif

#if UDE_MIC_KARAOK_EN
    if (usb_karaok_en) usb_karaok_en = false;
    bsp_karaok_exit(AUDIO_PATH_KARAOK);
#endif

    usb_device_exit();
    func_usbdev_exit_display();
#if UDE_SPEAKER_EN
    DACDIGCON0 &= ~BIT(6);
    adpll_spr_set(DAC_OUT_SPR);
    sys_cb.vol = f_ude.vol;         //recover system volume
    bsp_change_volume(sys_cb.vol);
    dac_fade_out();
    ude_mic_stop();
#endif // UDE_SPEAKER_EN
#if UDE_STORAGE_EN
    if (dev_is_online(DEV_SDCARD) || dev_is_online(DEV_SDCARD1)) {
        sd0_stop(1);
    #if I2C_MUX_SD_EN
        sd0_go_idle_state();
    #endif
    }
#endif // UDE_STORAGE_EN
#if SD_USB_MUX_IO_EN

    GPIOBPU300 = pu300_bak; GPIOBPU = pu_bak; GPIOBDIR = dir_bak;
    USBCON1 &=~ (BIT(17) | BIT(18) | BIT(19));
    FUNCMCON0 = SD0_MAPPING;
    delay_us(1);
#endif
	func_cb.last = FUNC_USBDEV;
#if UDE_HID_BACKSTAGE_EN
    if (dev_is_online(DEV_USBPC)) {
        delay_5ms(1);
        usb_device_enter(0x4);
    }
#endif
}

AT(.text.func.usbdev)
void func_usbdev(void)
{
    printf("%s\n", __func__);

    func_usbdev_enter();

    while (func_cb.sta == FUNC_USBDEV) {
        func_usbdev_process();
        func_usbdev_message(msg_dequeue());
        func_usbdev_display();
    }

    func_usbdev_exit();
}
#endif // FUNC_USBDEV_EN
